/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package routeprovider.Algoritmes;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import network.Base.PathElement;

/**
 *
 * @author Lega
 */

public class Dijkstra {

    // TODO: add throwing an exception if one of the parameters is null.
    public Dijkstra (Collection<PathElement> elements_) {
        elements = elements_;
    }

    // param shows wich search parametr will be used.
    public Collection<PathElement> getRoute (PathElement source_,
            PathElement dest_) {

        source = source_;
        dest = dest_;
        HashMap elementsPassed = new HashMap();

        Iterator it = elements.iterator();

        SearchElement searchSource, searchDest;

        for (PathElement p: elements) {

            if (p.equals(source)) {
                searchSource = new SearchElement(p);
                elementsPassed.put(p, searchSource);

            } else if (p.equals(dest)) {
                searchDest = new SearchElement(p);
                elementsPassed.put(p, searchDest);

            } else {
                elementsPassed.put(p, new SearchElement(p));
            }
        }

        DijkstraStep(searchSource, elementsPassed);

        // TODO: think about efficiently storing of path.
        return null;
    }

    public double getCost (PathElement source_, PathElement dest_) {

        source = source_;
        dest = dest_;
        HashMap elementsPassed = new HashMap();

        Iterator it = elements.iterator();

        SearchElement searchSource, searchDest;

        for (PathElement p: elements) {

            if (p.equals(source)) {
                searchSource = new SearchElement(p);
                searchSource.setValue(0);
                elementsPassed.put(p, searchSource);

            } else if (p.equals(dest)) {
                searchDest = new SearchElement(p);
                elementsPassed.put(p, searchDest);

            } else {
                elementsPassed.put(p, new SearchElement(p));
            }
        }

        DijkstraStep(searchSource, elementsPassed);

        return ((SearchElement) elementsPassed.get(dest)).getValue();
    }

    // TODO: add throwing an exception if e is null.
    void DijkstraStep (SearchElement e, HashMap elementsPassed) {
        if (e == null)
            return;

        if (e.passed())
            return;

        if (e.getElement().getConnections().isEmpty())
            return;

        for (PathElement p : e.getElement().getConnections()) {

            SearchElement currentElement  =
                    ((SearchElement)elementsPassed.get(p));

            if (currentElement.getValue() > (e.getValue() + p.getTimeDelay())) {
                currentElement.setValue(e.getValue() + p.getCost());
            }
        }

        e.setPassed();

        for (PathElement p : e.getElement().getConnections()) {
            DijkstraStep(((SearchElement)elementsPassed.get(p)),
                    elementsPassed);
        }
    }

    private class SearchElement {

        public SearchElement (PathElement element_) {
            element = element_;
            value = Double.POSITIVE_INFINITY;
            passed = false;
        }

        public boolean passed() {
            return passed;
        }

        public void setPassed () {
            passed = true;
        }

        public PathElement getElement () {
            return element;
        }

        public double getValue () {
            return value;
        }

        public void setValue (double value_) {
            value = value_;
        }

        private boolean passed;
        private PathElement element;
        private double value;
    }

    private PathElement source;
    private PathElement dest;
    private Collection<PathElement> elements;
}
